package com;

/**
 * 作者: 谢韬元
 * 日期: 2024/12/11
 * 类名: LoggingInvocationHandler
 */

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 日志记录InvocationHandler类
 * 该类实现了InvocationHandler接口，用于在方法调用前后添加日志记录功能
 */
public class LoggingInvocationHandler implements InvocationHandler {
    // 目标对象，即被代理的对象
    private final Object target;

    /**
     * 构造函数
     *
     * @param target 目标对象，即被代理的对象
     */
    public LoggingInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     * 调用方法并记录日志
     * 如果被调用的方法有Log注解，则记录开始和结束日志
     *
     * @param proxy  代理对象
     * @param method 被调用的方法
     * @param args   方法参数
     * @return 方法执行结果
     * @throws Throwable 方法执行过程中抛出的异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // 获取实现类中的方法信息
        Method methodTarget = target.getClass().getMethod(method.getName());
        // 判断方法上面是否有Log注解
        if (methodTarget.isAnnotationPresent(Log.class)) {
            // 获取方法名
            String methodName = method.getName();
            // 创建日期时间格式化器
            DateTimeFormatter formatter =
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
            // 记录开始时间
            LocalDateTime startTime = LocalDateTime.now();

            // 输出方法开始日志
            System.out.println("[LOG] Method: " + methodName + " started at: "
                    + startTime.format(formatter));

            // 调用目标方法并获取结果
            Object result = method.invoke(target, args);
            // 记录结束时间
            LocalDateTime endTime = LocalDateTime.now();
            // 计算执行时间
            long duration = java.time.Duration.between
                    (startTime, endTime).toMillis();

            // 输出方法结束日志
            System.out.println("[LOG] Method: " + methodName + " ended at: "
                    + endTime.format(formatter));
            // 输出方法执行时间日志
            System.out.println("[LOG] Method: " + methodName + " executed in: "
                    + duration + " ms");
            // 返回方法执行结果
            return result;
        } else {
            // 如果方法没有Log注解，直接调用目标方法并返回结果
            return method.invoke(target, args);
        }
    }
}